#ifndef MAPINFOQUERYOPTIMIZER_H
#define MAPINFOQUERYOPTIMIZER_H

#include <vector>

//#define MAPINFO_GLOBAL_TOLERANCE 1.0e-10 //used to determine if two double precision numbers are about equal

typedef std::vector<recno_list *> retval_stack;
typedef std::vector<FdoFilter*> filter_stack;

class MapInfoClassDefinition;

struct Bounds
{
public:

    double minx;
    double miny;
    double maxx;
    double maxy;

public:
    Bounds()
    {
        //undefined rectangle -- arbitrarily define as maxx is smaller than minx
        minx = 0.0;
        maxx = -1.0;
        miny = 0.0;
        maxy = -1.0;
    }

    Bounds(double dminx, double dminy, double dmaxx, double dmaxy)
    {
        _ASSERT(dminx <= dmaxx);
        _ASSERT(dminy <= dmaxy);

        minx = dminx;
        miny = dminy;
        maxx = dmaxx;
        maxy = dmaxy;
    }
};


class MapInfoQueryOptimizer : public FdoIFilterProcessor, public FdoIExpressionProcessor
{
public:

    MapInfoQueryOptimizer(MapInfoClassDefinition * pMapInfoClassDef);
    ~MapInfoQueryOptimizer();

protected:

    virtual void Dispose();

public:

    //--------------------------------------------------------------------
    // FdoIFilterProcessor
    //--------------------------------------------------------------------

    virtual void ProcessBinaryLogicalOperator(FdoBinaryLogicalOperator& filter);

    virtual void ProcessUnaryLogicalOperator(FdoUnaryLogicalOperator& filter);

    virtual void ProcessComparisonCondition(FdoComparisonCondition& filter);

    virtual void ProcessInCondition(FdoInCondition& filter);

    virtual void ProcessNullCondition(FdoNullCondition& filter);

    virtual void ProcessSpatialCondition(FdoSpatialCondition& filter);

    virtual void ProcessDistanceCondition(FdoDistanceCondition& filter);


    //--------------------------------------------------------------------
    // FdoIExpressionProcessor
    //--------------------------------------------------------------------

    virtual void ProcessBinaryExpression(FdoBinaryExpression& expr);

    virtual void ProcessUnaryExpression(FdoUnaryExpression& expr);

    virtual void ProcessFunction(FdoFunction& expr);

    virtual void ProcessIdentifier(FdoIdentifier& expr);

    virtual void ProcessComputedIdentifier(FdoComputedIdentifier& expr) { return; }

    virtual void ProcessParameter(FdoParameter& expr);

    virtual void ProcessBooleanValue(FdoBooleanValue& expr);

    virtual void ProcessByteValue(FdoByteValue& expr);

    virtual void ProcessDateTimeValue(FdoDateTimeValue& expr);

    virtual void ProcessDecimalValue(FdoDecimalValue& expr);

    virtual void ProcessDoubleValue(FdoDoubleValue& expr);

    virtual void ProcessInt16Value(FdoInt16Value& expr);

    virtual void ProcessInt32Value(FdoInt32Value& expr);

    virtual void ProcessInt64Value(FdoInt64Value& expr);

    virtual void ProcessSingleValue(FdoSingleValue& expr);

    virtual void ProcessStringValue(FdoStringValue& expr);

    virtual void ProcessBLOBValue(FdoBLOBValue& expr);

    virtual void ProcessCLOBValue(FdoCLOBValue& expr);

    virtual void ProcessGeometryValue(FdoGeometryValue& expr);

public:

    //-----------------------------------------------------------------
    // MapInfoQueryOptimizer
    //-----------------------------------------------------------------

    recno_list* GetResult();
    FdoFilter* GetOptimizedFilter();

private:

    //helper functions
    recno_list* DoSecondaryFilter(FdoIGeometry *filterGeom, FdoSpatialOperations spatialOp, recno_list* res);
    recno_list* GetAllMatchesVector(OGRAttrIndex* pAttrIndex, OGRField *psKey);
    recno_list* RecnoFromKey(FdoPropertyValueCollection* keyvals = NULL);
    recno_list* recno_list_union(recno_list* left, recno_list* right);
    recno_list* recno_list_intersection(recno_list* left, recno_list* right);
    bool SearchKey(TABFile *pTABFile, FdoIdentifier * ident, FdoDataValue * val, FdoComparisonOperations oper, recno_list* recno);
    bool IsAxisAlignedRectangle(FdoIGeometry* geom, double xTolerance, double yTolerance);
    bool AreEqual(double d1, double d2, double tolerance);

    //working set of features and key property values
    retval_stack m_retvals;
    FdoPropertyValueCollection* m_keyvals;
    FdoDataPropertyDefinitionCollection* m_idprops;
    filter_stack m_filters;

    IMapInfoFile * m_pMapInfoFile;
    MapInfoClassDefinition * m_pMapInfoClass;
};

#endif
